/**
 * @file
 * @author  Tsin Smith <tsin.creator@gmail.com>
 *
 * @section DESCRIPTION
 *
 * An abstract interface for display.
 *
 */

#ifndef __TSIN_DISPLAY_DISPLAY_HPP__
#define __TSIN_DISPLAY_DISPLAY_HPP__

#include <tsin/display/common.hpp>

#include <tsin/util/Resolution.hpp>
#include <tsin/display/DisplayObject.hpp>

namespace tsin {

        class Config;
        class GameViewport;
        class Image;
        class DecoratedImage;

        static const float zNear = -1, zFar = -9, zMid = (zNear + zFar)/2;

        enum BlendStyle {
                COVERING = 0,
                OVERPRINTING,
                BLEND_DEFAULT = 100
        };

        /**
         * @class Display
         * @ingroup display
         * @brief Graphic user interface for TSIN.
         *
         * @par Model
         * The interface uses a double buffer model. One buffer is displayed,
         * called 'display-buffer', while modifications are carried out on the
         * other, called 'modification-buffer'. Updating is done by swapping
         * their position.
         *
         * @par Overall Reference Frame
         * The overall reference frame's origin is located at the center of the
         * window, with the x axis going right and y axis up. The range of valid
         * coordinates depends on the aspect ratio of the window. Here's a list
         * of defined coordinate ranges and corresponding resolution.
         *   - 4:3
         *      - Resolution: 640 x 480
         *      - X coord range: [-32, 32]
         *      - Y coord range: [-24, 24]
         *   - 16:9
         *      - Resolution: 800 x 450
         *      - X coord range: [-40, 40]
         *      - Y coord range: [-22.5, 22.5]
         * This reference frame is for 2D drawing with z = 0 and follows the
         * painter's policy.
         *
         * @par Per-viewport Reference Frame
         * Each view port has its own reference frame with the center as its
         * origin, x axis going right and y axis going up. The range of coords
         * is determined according to the overall frame it resides in.
         *
         * @see GameViewport
         *
         */
        class DISPLAY_DLLEXPORT Display
        {
        public:
                enum {
                        HORIZONTAL_LEFT = 0x01,
                        HORIZONTAL_CENTER = 0x02,
                        HORIZONTAL_RIGHT = 0x04,
                        VERTICAL_BOTTOM = 0x10,
                        VERTICAL_CENTER = 0x20,
                        VERTICAL_TOP = 0x40
                };

                virtual ~Display() {}

                /**
                 * Initialize display using the config given.
                 *
                 * @param config Configuration info
                 *
                 * @return true if inititialization succeeds.
                 */
                virtual bool init(const Config &config) = 0;

                /**
                 * @name Window Management
                 */
                //@{

                /**
                 * Set name of the window.
                 *
                 * @param name The C-style string to be set.
                 *
                 * @return true if the setting succeeds.
                 */
                virtual bool setWindowName(const char *name) = 0;

                /**
                 * Set icon of the window.
                 *
                 * @param path The path (absolute or relative) of the icon
                 * image. Should support at least ico and png files.
                 *
                 * @return true if the operation succeeds.
                 */
                virtual bool setWindowIcon(const char *path) = 0;

                /**
                 * Clear the whole display. Carried out on the
                 * modification-buffer.
                 *
                 * @return true if the operation succeeds.
                 */
                virtual bool clear() = 0;

                /**
                 * Update the whole display by swapping display-buffer and
                 * modification-buffer.
                 *
                 * @return true if the operation succeeds.
                 */
                virtual bool update() = 0;

                //@} Window Management

                /**
                 * @name Reference Frame Switching
                 */
                //@{
                /**
                 * Interpret coords afterwards in the overall reference frame.
                 */
                virtual void useOverallFrame() = 0;

                /**
                 * Interpret coords afterwards in the viewport given.
                 *
                 * This is the default state after the display manager is
                 * initialized.
                 */
                virtual void useViewportFrame(GameViewport &viewport) = 0;
                //@} Reference Frame Switching

                /**
                 * @name Image Blitting
                 */
                //@{

                virtual Image *openImage(const char *path, StandardResolution res) = 0;

                /**
                 * Blit the image given to the specified position.
                 *
                 * The coords given is interpreted in the mostly selected frame
                 * by using useOverallFrame() or useViewportFrame().
                 */

                virtual void blitImage(Image &image, float x, float y, 
                                       float width, float height,
                                       float angle = 0.0, float z = zMid) = 0;

                /**
                 * Blit a decorated image given to the specified position.
                 *
                 * The coords given is interpreted in the mostly selected frame
                 * by using useOverallFrame() or useViewportFrame().
                 */
                virtual void blitImage(DecoratedImage &image, float x, float y,
                                       float width, float height, float angle = 0.0f,
                                       float z = zMid, int align = HORIZONTAL_LEFT | VERTICAL_BOTTOM) = 0;
                virtual void blitImage(DecoratedImage &image, DisplayObject *object);
                //@} Image Blitting
        };

};

#endif /* __TSIN_DISPLAY_DISPLAY_HPP__ */
